package com.tianji.learning.utils;

import com.tianji.common.utils.JsonUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import io.swagger.models.auth.In;
import jdk.jfr.Percentage;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.DelayQueue;

@Component
@Slf4j
@RequiredArgsConstructor(onConstructor_ ={@Lazy} )
public class LearningRecordDelayTaskHandel {

    private final StringRedisTemplate template;
    private final static String RECORD_KEY_TEMPLATE="lesson_record:{}";
    private final DelayQueue<DelayTask<RecordTaskData>> delayQueue=new DelayQueue<>();
    private static volatile Boolean begin=false;
    private final LearningRecordMapper recordMapper;
    private final ILearningLessonService learningLessonService;

    /**
     * 类初始化完成就运行下面的方法
     */
    @PostConstruct
    public void init(){
        CompletableFuture.runAsync(this::handelDelayTask);
    }

    /**
     * 在程序结束前会执行下面的方法
     */
    @PreDestroy
    public void destroy(){
        begin=false;
        log.debug("延迟任务停止执行");
    }

    /**
     * 处理异步延迟任务
     */
    public void handelDelayTask(){
        while (begin) {
            // 获取异步延迟任务
            try {
                DelayTask<RecordTaskData> take = delayQueue.take();
                RecordTaskData data = take.getData();
                // 2.读取redis数据
                LearningRecord record = readRecordCache(data.getLessonId(), data.getId());
                // 3.数据为空则继续下一次循环
                if (record==null){
                    continue;
                }
                // 4.数据不为空则比较moment数值是否相同
                if (!record.getMoment().equals(data.getMoment())){
                    // 4.1moment数值不相同则更新redis缓存数据
                    writeLearningRecord(record);
                }
                // 4.2moment数值相同则判断为用户离开视频播放页面 更新数据库数据
                record.setFinished(null);
                // 更新学习记录
                recordMapper.updateById(record);
                // 更新课表信息
                LearningLesson lesson = new LearningLesson();
                lesson.setLatestLearnTime(LocalDateTime.now());
                lesson.setLatestSectionId(data.getId());
                lesson.setId(data.getId());
                learningLessonService.updateById(lesson);
            } catch (Exception e) {
                log.error("处理延迟任务发生异常", e);
            }
        }

    }
    /**
     * 添加学习记录到redis
     * @param learningRecord
     */
    public void addLearningRecordTask(LearningRecord learningRecord){
        // 1.向redis写入学习记录
        writeLearningRecord(learningRecord);
        // 2.提交延时任务 20s比较一次
        delayQueue.add(new DelayTask<>(new RecordTaskData(learningRecord),Duration.ofSeconds(20)));
    }

    /**
     * 向redis更新学习记录的缓存数据
     * @param learningRecord
     */
    public void writeLearningRecord(LearningRecord learningRecord) {
        log.debug("更新学习记录的缓存数据");
        try {
            // 将hashValue 转为JSON格式
            String json = JsonUtils.toJsonStr(new RecordCacheData(learningRecord));
            // 写入redis
            String key= StringUtils.format(RECORD_KEY_TEMPLATE,learningRecord.getId());
            template.opsForHash().put(key,learningRecord.getSectionId(),json);
            // 添加缓存过期时间
            template.expire(key, Duration.ofMinutes(1));
        } catch (Exception e) {
            log.debug("更新学习记录的缓存数据失败",e);
        }
    }

    /**
     * 向redis读取数据
     * @param lessonId
     * @param sectionId
     * @return
     */
    public LearningRecord readRecordCache(Long lessonId,Long sectionId){
        try {
            // 向redis中读取对应数据
            String key= StringUtils.format(RECORD_KEY_TEMPLATE,sectionId);
            Object json = template.opsForHash().get(key, sectionId);
            // 数据为空 则返回null
            if (json==null){
                return null;
            }
            // 数据不为空 数据转换和检查
            return JsonUtils.toBean(json.toString(),LearningRecord.class);
        } catch (Exception e) {
            log.debug("数据读取异常",e);
            return null;
        }
    }

    public void deleteRecordCache(Long lessonId,Long sectionId){

        // 删除数据
        String key=StringUtils.format(RECORD_KEY_TEMPLATE,sectionId);
        template.opsForHash().delete(key,sectionId);
    }
    @Data
    @NoArgsConstructor
    public class RecordCacheData{
        private Long id;
        private Boolean finished;
        private Integer moment;

        public RecordCacheData(LearningRecord record) {
            this.id = record.getId();
            this.finished = record.getFinished();
            this.moment = record.getMoment();
        }
    }

    @Data
    @NoArgsConstructor
    public class RecordTaskData{
        private Long lessonId;
        private Long id;
        private Integer moment;

        public RecordTaskData(LearningRecord record) {
            this.lessonId = record.getLessonId();
            this.id = record.getSectionId();
            this.moment = record.getMoment();
        }
    }
}
